package com.platform.boot.security.user;

import cn.hutool.core.util.IdUtil;
import com.platform.boot.utils.BaseAutoToolsUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class UsersService extends BaseAutoToolsUtil {

    private final UsersRepository usersRepository;

    public Flux<UserOnly> search(UserRequest userRequest, Pageable pageable) {
        return entityTemplate.select(Query.query(userRequest.toCriteria()).with(pageable), User.class)
                .map(UserOnly::withUser);
    }

    public Mono<Page<UserOnly>> page(UserRequest userRequest, Pageable pageable) {
        return search(userRequest, pageable).collectList()
                .zipWith(entityTemplate.count(Query.query(userRequest.toCriteria()), User.class))
                .map(entityTuples -> new PageImpl<>(entityTuples.getT1(), pageable, entityTuples.getT2()));
    }

    public Mono<User> loadByUsername(String username) {
        return usersRepository.findByUsernameIgnoreCase(username);
    }

    public Mono<User> operate(UserRequest userRequest) {
        return this.usersRepository.findByUsernameIgnoreCase(userRequest.getUsername())
                .flatMap(old -> this.save(userRequest.id(old.getId()).toUser()))
                .switchIfEmpty(this.save(userRequest.buildPassword().toUser()));
    }

    public Mono<Void> delete(UserRequest userRequest) {
        return usersRepository.delete(userRequest);
    }

    public Mono<User> save(User user) {
        if (user.isNew()) {
            user.setCode(IdUtil.fastUUID());
            return this.usersRepository.save(user);
        } else {
            assert user.getId() != null;
            return this.usersRepository.findById(user.getId())
                    .flatMap(old -> {
                        user.setCreatedTime(old.getCreatedTime());
                        user.setPassword(old.getPassword());
                        user.setCode(old.getCode());
                        return this.usersRepository.save(user);
                    });
        }
    }

}